package com.elnguage.lox;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.List;
import java.util.Random;

class Environment {
    
    protected Map<String, Object> values = null;
    protected Environment enclosing = null;

    public Environment()
    {
        this.values = new HashMap<>();
        this.enclosing = null;
    }
    
    public Environment(Environment enclosing) {
        this.values = new HashMap<>();
        this.enclosing = enclosing;
      }

    protected Object get(Token name) {
    if (values.containsKey(name.lexeme)) {
      return values.get(name.lexeme);
    }
    if (enclosing != null) return enclosing.get(name);
    throw new RuntimeError(name,
        "Undefined variable '" + name.lexeme + "'.");
  }

  protected void assign(Token name, Object value) {
    if (values.containsKey(name.lexeme)) {
      values.put(name.lexeme, value);
      return;
    }
    if (enclosing != null) {
        enclosing.assign(name, value);
        return;
      }

    throw new RuntimeError(name,
        "Undefined variable '" + name.lexeme + "'.");
  }

  void define(String name, Object value) 
  {
    values.put(name, value);
  }

}

class StellaGlobalEnvironment extends Environment
{
  int global_tick = 0;
  List<StellaCountryEnvironment> country_list = new ArrayList<StellaCountryEnvironment>();
  List<StellaPlanetEnvironment> planet_list = new ArrayList<StellaPlanetEnvironment>();
  Map<Environment, List<StellaEvent>> tick_regist_event = new HashMap<>();

  public int GetGlobalTick()
  {
    return global_tick;
  }
  public void SetGlobalTick(int time)
  {
    global_tick = time;
  }
  public Environment GetEnvByName(String name)
  {
    for (StellaCountryEnvironment stellaCountryEnvironment : country_list) {
      if(stellaCountryEnvironment.values.get("name").equals(name))
      {
        return stellaCountryEnvironment;
      }
    }
    for (StellaPlanetEnvironment stellaPlanetEnvironment : planet_list) {
      if(stellaPlanetEnvironment.values.get("name").equals(name))
      return stellaPlanetEnvironment;
    }
    return null;
  }
  public StellaGlobalEnvironment()
  {
    super();
    InitCountryPlanets(4, 16);
    this.values.put("time", 0);

    this.values.put("country", country_list);
    this.values.put("planet", planet_list);
  }
  private void InitCountryPlanets(int cnum, int pnum)
  {
    Random random = new Random();
    for(int i=0; i<cnum; i++)
    {
      StellaCountryEnvironment env = new StellaCountryEnvironment(String.format("country_%d", i), 1000 + random.nextInt(9000));
      this.country_list.add(env);
      tick_regist_event.put(env, new ArrayList<StellaEvent>());
    }
    for(int i=0; i<pnum; i++)
    {
      StellaPlanetEnvironment env = new StellaPlanetEnvironment(String.format("planet_%d", i), random.nextInt(10));
      this.planet_list.add(env);
      tick_regist_event.put(env, new ArrayList<StellaEvent>());
    }
  }
}

class StellaCountryEnvironment extends Environment
{
  public StellaCountryEnvironment(String countryName, int InitCoin)
  {
    super();
    this.values.put("name", countryName);
    this.values.put("territory", null);
    this.values.put("coin", InitCoin);
    this.values.put("coin_gain", 0);
  }  
}

class StellaPlanetEnvironment extends Environment
{
  public StellaPlanetEnvironment(String planetName, int InitResources)
  {
    super();
    this.values.put("name", planetName);
    this.values.put("resource", InitResources);
    this.values.put("owner", null);
  }
}